/*===============================================
*   文件名称：ohd_client.c
*   创 建 者：     
*   创建日期：2024年08月30日
*   描    述：
================================================*/
#include "head.h"

//void showfile();
void showtab();
void download();
void upload(int sockfd);
void _upload(int sockfd);
char* dealpath(char* str);
bool isregular(char * path);
void fileupload(int sockfd,char* filepath);
unsigned long int getsize(char * path);
void checkohd(int sockfd);
void download(int sockfd);
bool cmpsize(char * filename,unsigned long int filesize);

bool cmpsize(char * filename,unsigned long int filesize)
{
    struct stat statbuf;
    if(stat(filename,&statbuf)<0)
    {
        perror("cmpsize stat");
        return false;
    }
    return statbuf.st_size == filesize;
}

void download(int sockfd)
{
    char filename[256];
    while(1)
    {
        printf("请输入要下载的文件名:");
        scanf("%s",filename);
        int send = write(sockfd,filename,sizeof(filename));
        if(send < 0)
        {
            perror("download send");
            continue;
        }
        char ret;
        while(1)
        {
            read(sockfd,&ret,sizeof(ret));
            if(ret == 'f')
            {
                printf("没有此文件!退出下载!\n");
                return;
            }
            if(ret == 's')
            {
                printf("开始下载文件!\n");
                printf("获取文件大小!\n");
                unsigned long int filesize;
                if(read(sockfd,&filesize,sizeof(filesize))<0)
                {
                    printf("文件大小获取失败!\n");
                }else
                {
                    printf("文件大小为: %lu\n",filesize);
                    printf("文件名为: %s\n",filename);
                    int fd = open(filename,O_WRONLY|O_TRUNC|O_CREAT,0664);
                    if(fd < 0)
                    {
                        perror("download open");
                    }
                    int buf[101];
                    printf("开始下载文件!\n");
                    while(!cmpsize(filename,filesize))
                    {
                        int rec = read(sockfd,buf,sizeof(buf)-1);
                        if(rec < 0)
                            perror("download read");
                        write(fd,buf,rec);
                    }
                    close(fd);
                    printf("下载完成!\n");
                    return;
                }
                
            }

        }
    }
}

void checkohd(int sockfd)
{
    printf("开始接收网盘目录：\n");
    char filename[256];
    printf("*************************************\n");
    while(1)
    {
        //memset(buf,'\0',sizeof(buf));
        int rec = read(sockfd,filename,sizeof(filename));
        if(rec < 0)
        {
            perror("checkohd read");
        }
        if(strcmp(filename,"end")==0)
        {
            printf("*************************************\n");
            printf("接收完毕!\n");
            break;
        }
        printf("file:%s \n",filename);
    }
}

unsigned long int getsize(char * path)
{
    struct stat statbuf;
    if(stat(path,&statbuf)<0)
    {
        perror("stat");
        return -1;
    }

    //printf("size:%lu\n",statbuf.st_size);
    return statbuf.st_size;
}

void fileupload(int sockfd,char* filepath)
{
    int fd1 = open(filepath,O_RDONLY);
    if(fd1 < 0)
    {
        perror("open src failed");
        return;
    }
    int buf[101];
    while(1)
    {
        int ret = read(fd1,buf,sizeof(buf)-1);
        if(ret < 0)
        {
            perror("read failed");
            return;
        }else
        {
            if(0 == ret)
                break;
            write(sockfd,buf,ret);
            /*size_t rec = 0;
            while(rec != 4)
            {
                read(sockfd,&rec,sizeof(size_t));
            }*/
        }
    }
    char rec = 'w';
    while(rec != 'e')
    {
        read(sockfd,&rec,sizeof(int));
    }
    printf("上传完成\n");
    close(fd1);
}

bool isregular(char * path)
{
    struct stat statbuf;
    if(stat(path,&statbuf)<0)
    {
        perror("stat");
        return false;
    }

    //printf("size:%lu\n",statbuf.st_size);
    if(S_ISREG(statbuf.st_mode))
    {
        //printf("This is a regular file!\n");
        return true;
    }else
        //printf("This is not a regular file!\n");
        return false;
}

void showtab()
{
    printf("***************************************\n");
    printf("1.上传文件 2.下载文件\n");
    printf("3.查看网盘目录\n");
    printf("0.退出程序\n");
    printf("***************************************\n");
}

void upload(int sockfd)
{
    int opt;
    while(1)
    {
        printf("***************************************\n");
        printf("1.显示网盘目录  2.上传文件\n");
        printf("0.结束上传\n");
        printf("请输入对应选项：\n");
        printf("***************************************\n");
        scanf("%d",&opt);
        switch(opt)
        {
            case 1:
                write(sockfd,&opt,sizeof(opt));
                checkohd(sockfd);
                break;
            case 2:
                write(sockfd,&opt,sizeof(opt));
                _upload(sockfd);
                break;
            case 0:
                write(sockfd,&opt,sizeof(opt));
                return;
            default:
                break;
        }
    }
}

char* dealpath(char * str)
{
    char* ret = str;
    for(int i = 0;i<strlen(str);++i)
    {
        if(str[i] == '/')
            ret = str + i;
    }
    if(*(ret + 1) == '\0'||ret == str)
        return NULL;
    else
        return ret + 1;
}

void _upload(int sockfd)
{
    char path[101];
    while(1)
    {
        //memset(path,'\0',sizeof(path));
        printf("请输入文件路径:\n");
        scanf("%s",path);
        char filename[256];
        char * src = dealpath(path);
        if(src == NULL)
        {
            printf("无效路径！\n");
            continue;
        }else
        {
            strcpy(filename,src);
            printf("文件名为：%s\n",filename);
        }
        
        /*DIR* dirp = opendir(path);
        if(dirp == NULL)
        {
            perror("opendir");
            printf("无效路径！\n");
            continue;
        }*/
        if(!isregular(path))
        {
            printf("不是有效文件\n");
            continue;
        }
        unsigned long int filesize = getsize(path);
        if(filesize == -1)
        {
            printf("文件过大或文件大小获取失败!\n");
            continue;
        }else
        {
            printf("文件大小为：%lu\n",filesize);
        }
        if(write(sockfd,&filesize,sizeof(filesize))<0)
        {
        	perror("filesize write");
        	continue;
        }else
        {
            printf("文件大小发送成功!\n");
        }
        
        int send = write(sockfd,filename,sizeof(filename));
        if(send < 0)
        {
            perror("write:");
        }else
        {
            printf("文件名发送成功!\n");
            char rec = 'w';
            while(rec!='e')
            {
                read(sockfd,&rec,sizeof(rec));
            }
            printf("服务器成功接收，开始文件传输!\n");
            fileupload(sockfd,path);
            break;
        }
    }
}

int main(int argc, char *argv[])
{ 
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0)
    {
        perror("socket");
        return -1;
    }
    printf("socket success!\n");

    //connect server
    struct sockaddr_in srvaddr;
    memset(&srvaddr, 0, sizeof(srvaddr)); //清空结构体
    srvaddr.sin_family = AF_INET; //地址族IPv4
    srvaddr.sin_port = htons(5500); //端口号
    srvaddr.sin_addr.s_addr = inet_addr("192.168.79.130"); //sever IP地址
    
    if(connect(sockfd, (struct sockaddr*)&srvaddr, sizeof(srvaddr))<0)
    {
        perror("connect");
        return -1;
    }
    printf("connect success!\n");
    int opt;
    while(1)
    {
        showtab();
        printf("请输入对应选项：");
        scanf("%d",&opt);
        switch(opt)
        {
            case 1:
                write(sockfd,&opt,sizeof(opt));
                upload(sockfd);
                break;
            case 2:
                write(sockfd,&opt,sizeof(opt));
                download(sockfd);
                break;
            case 3:
                write(sockfd,&opt,sizeof(opt));
                checkohd(sockfd);
                break;
            case 0:
                write(sockfd,&opt,sizeof(opt));
                close(sockfd);
                return 0;
            default:
                break;
        }
    }
    return 0;
} 
